#!/bin/bash
# Build docker image
# Copyright (c) MarsBighead, 2024. All rights reserved.
#
#openGauss is licensed under Mulan PSL v2.
#You can use this software according to the terms and conditions of the Mulan PSL v2.
#You may obtain a copy of Mulan PSL v2 at:
#
#          http://license.coscl.org.cn/MulanPSL2
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.
#-------------------------------------------------------------------------
#
# entrypint.sh
#    Build docker image
#
# IDENTIFICATION
#    phant-container/images/entrypint.sh
#
#-------------------------------------------------------------------------

# set -eu
set -Eeo pipefail
# GAUSSHOME is the home path of which openGuass binary is installed, and it should be a fixed directory in an image
# GAUSSHOME has been decleared in Dockerfile
# declare GAUSSHOME=${GAUSSHOME:-/opt/openGauss}

declare GAUSSDATA=${GAUSSDATA:-/opt/data}
# Suport recovery from env variables
declare GS_PORT=${GS_PORT:-5432}
# GS_USER is initial user 
declare GS_USER=${GS_USER:-omm}

declare PWFILE=$GAUSSDATA/.pwfile

declare cluster_state=""
# declare GS_REPLUSER=${GS_REPLUSER:-sufe}
# GS_USERNAME is sysadmin user with remote access,
#             and it can be empty if no remote access requirements 
# declare GS_USERNAME=${GS_USERNAME:-hbu}

hostname=$(hostname)

current_dir=$(cd $(dirname $0); pwd)
cd ${current_dir}
#source lib.sh

function file_env() {
    local var="$1"
    local fileVar="${var}_FILE"
    local def="${2:-}"
    if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then
        echo >&2 "error: both $var and $fileVar are set (but are exclusive)"
        exit 1
    fi
    local val="$def"
    if [ "${!var:-}" ]; then
        val="${!var}"
    elif [ "${!fileVar:-}" ]; then
        val="$(< "${!fileVar}")"
    fi
    export "$var"="$val"
    unset "$fileVar"
}

# check to see if this file is being run or sourced from another script
function _is_sourced() {
    [ "${#FUNCNAME[@]}" -ge 2 ] \
       && [ "${FUNCNAME[0]}" = '_is_sourced' ] \
       && [ "${FUNCNAME[1]}" = 'source' ]
}

########################
## Init OpenGauss ENV ##
########################

# Loads various settings that are used elsewhere in the script
# This should be called before any other functions
function docker_setup_env() {

    file_env 'GS_PASSWORD'
 
    # file_env 'GS_USER' 'omm'
    file_env 'GS_DB' "$GS_USER"
    file_env 'POSTGRES_INITDB_ARGS'
    # default authentication method is md5
    : "${GS_HOST_AUTH_METHOD:=md5}"
    if [ $(uname) == "Linux" ]; then 
        declare -g DATABASE_ALREADY_EXISTS
    fi
    # look specifically for OG_VERSION, as it is expected in the DB dir
    if [ -s "$PGDATA/PG_VERSION" ]; then
       DATABASE_ALREADY_EXISTS='true'
    fi
}

# USER level env variables 
function set_envfile() {

    export ENVFILE=${ENVFILE:-/home/omm/.bashrc}
    export USER=omm
    export GROUP=omm
    # GAUSS_EDITION only in patch phase
    #export GAUSS_EDITION=lite
   
    #GPHOME: tool path, used by openGauss-OM
    export GPHOME=${GPHOME}
    export CM_HOME=${CM_HOME}
    
    export PGDATA=${GAUSSDATA}/openGauss
    export PGHOST=${GAUSSDATA}/tmp
    export GAUSSLOG=${GAUSSDATA}/gausslog
    
    # Customized directories
    export GAUSS_CM_DIR=${GAUSSDATA}/cm
    
    # GS_CLUSTER_NAME used by OM configuration xml 
    export GS_CLUSTER_NAME=${GS_CLUSTER_NAME:-cluster}

    export PATH=${GAUSSHOME}/bin:${CM_HOME}/bin:${GPHOME}/script/gspylib/pssh/bin:${GPHOME}/script:$PATH
    export LD_LIBRARY_PATH=${GAUSSHOME}/lib:${CM_HOME}/lib:${GPHOME}/lib:${LD_LIBRARY_PATH}
    export PYTHONPATH=$GPHOME/lib
    export GAUSS_ENV=2
    if [ $(grep $PATH ~/.bashrc  | grep $GPHOME | wc -l) -gt 0 ];then
        source ${ENVFILE}
    else
    cat >>  ${ENVFILE} <<EOF 
export PGDATA=${PGDATA}
export PGHOST=${PGHOST}
export GAUSSLOG=${GAUSSLOG}

export GAUSS_CM_DIR=${GAUSS_CM_DIR}

# lib variables under local user
export GPHOME=${GPHOME}
export CM_HOME=${CM_HOME}

export PATH=${GAUSSHOME}/bin:${GPHOME}/script/gspylib/pssh/bin:${GPHOME}/script:$PATH
export LD_LIBRARY_PATH=${GAUSSHOME}/lib:${GPHOME}/lib:${LD_LIBRARY_PATH}
export PYTHONPATH=${PYTHONPATH}

export GAUSS_ENV=2
export GS_CLUSTER_NAME=${GS_CLUSTER_NAME}
EOF
    fi 
#HOST INFO should be configured when launch container process" 
#export PRIMARYHOST=${primary_host} 
#export STANDBYHOSTS=${standby_hosts}
#export PRIMARYNAME=${primary_name}
#export STANDBYNAMES=${standby_names} 
}

function _opengauss_want_help() {
    local arg
    count=1
    for arg; do
        case "$arg" in
        # postgres --help | grep 'then exit'
        # leaving out -C on purpose since it always fails and is unhelpful:
        # postgres: could not access the server configuration file "/var/lib/postgresql/data/postgresql.conf": No such file or directory
            -'?'|--help|--describe-config|-V|--version)
                return 0
                ;;
            esac
        if [ "$arg" == "-M" ]; then
            SERVER_MODE=${@:$count+1:1}
            echo "openGauss DB SERVER_MODE = $SERVER_MODE"
            shift
        fi
        count=$[$count + 1]
    done
    return 1
}
####################
## Init OpenGauss ##
####################

# print large warning if GS_PASSWORD is long
# error if both GS_PASSWORD is empty and GS_HOST_AUTH_METHOD is not 'trust'
# print large warning if GS_HOST_AUTH_METHOD is set to 'trust'
# assumes database is not set up, ie: [ -z "$DATABASE_ALREADY_EXISTS" ]
function docker_verify_minimum_env() {
    # check password first so we can output the warning before postgres
    # messes it up
    if [[ "$GS_PASSWORD" =~  ^(.{8,}).*$ ]] &&  [[ "$GS_PASSWORD" =~ ^(.*[a-z]+).*$ ]] && [[ "$GS_PASSWORD" =~ ^(.*[A-Z]).*$ ]] &&  [[ "$GS_PASSWORD" =~ ^(.*[0-9]).*$ ]] && [[ "$GS_PASSWORD" =~ ^(.*[#?!@$%^&*-]).*$ ]]; then
            cat >&2 <<-'EOWARN'

        Message: The supplied GS_PASSWORD is meet requirements.

EOWARN
    else
             cat >&2 <<-'EOWARN'

        Error: The supplied GS_PASSWORD is not meet requirements.
        Please Check if the password contains uppercase, lowercase, numbers, special characters, and password length(8).
        At least one uppercase, lowercase, numeric, special character.
        Example: Enmo@123
EOWARN
        exit 1
    fi
    if [ -z "$GS_PASSWORD" ] && [ 'trust' != "$GS_HOST_AUTH_METHOD" ]; then
        # The - option suppresses leading tabs but *not* spaces. :)
        cat >&2 <<-'EOE'
        Error: Database is uninitialized and superuser password is not specified.
               You must specify GS_PASSWORD to a non-empty value for the
               superuser. For example, "-e GS_PASSWORD=password" on "docker run".

               You may also use "GS_HOST_AUTH_METHOD=trust" to allow all
               connections without a password. This is *not* recommended.

EOE
        exit 1
    fi
    if [ 'trust' = "$GS_HOST_AUTH_METHOD" ]; then
        cat >&2 <<-'EOWARN'
        ********************************************************************************
        WARNING: GS_HOST_AUTH_METHOD has been set to "trust". This will allow
                 anyone with access to the opengauss port to access your database without
                 a password, even if GS_PASSWORD is set.
                 It is not recommended to use GS_HOST_AUTH_METHOD=trust. Replace
                 it with "-e GS_PASSWORD=password" instead to set a password in
                 "docker run".
        ********************************************************************************
EOWARN
    fi
}

function docker_init_pwfile(){
    if [ -f $PWFILE ];then
        echo "$PWFILE has been created, skip init..." 
    else
        echo "Create pwfile $PWFILE" 
        printf $GS_PASSWORD | sed s/^\'// | sed s/\'$// > $PWFILE
    fi
}

function docker_clean_pwfile(){
    if [ -f $PWFILE ];then
        rm -rf $PWFILE
    fi
}

# initialize empty PGDATA directory with new database via 'initdb'
# arguments to `initdb` can be passed via POSTGRES_INITDB_ARGS or as arguments to this function
# `initdb` automatically creates the "postgres", "template0", and "template1" dbnames
# this is also where the database user is created, specified by `GS_USER` env
function docker_init_database() {
    # "initdb" is particular about the current user existing in "/etc/passwd", so we use "nss_wrapper" to fake that if necessary
    if ! getent passwd "$(id -u)" &> /dev/null && [ -e /usr/lib/libnss_wrapper.so ]; then
        export LD_PRELOAD='/usr/lib/libnss_wrapper.so'
        export NSS_WRAPPER_PASSWD="$(mktemp)"
        export NSS_WRAPPER_GROUP="$(mktemp)"
        echo "postgres:x:$(id -u):$(id -g):PostgreSQL:$PGDATA:/bin/false" > "$NSS_WRAPPER_PASSWD"
        echo "postgres:x:$(id -g):" > "$NSS_WRAPPER_GROUP"
    fi

    if [ -n "$POSTGRES_INITDB_XLOGDIR" ]; then
        set -- --xlogdir "$POSTGRES_INITDB_XLOGDIR" "$@"
    fi

    docker_init_pwfile
    if [ -z "$GS_NODENAME" ]; then
        GS_NODENAME=gaussdb
    fi 
    # eval 'gs_initdb --pwfile=<(echo "$GS_PASSWORD") --nodename=gaussdb '"$POSTGRES_INITDB_ARGS"' "$@"'
    cat <<EOF
        GS_NODENAME=$GS_NODENAME 
        'gs_initdb  --pwpasswd=$PWFILE --nodename=$GS_NODENAME -D $PGDATA"'
EOF
    eval 'gs_initdb --pwfile=$PWFILE --nodename=$GS_NODENAME -D $PGDATA'
    docker_clean_pwfile
    # unset/cleanup "nss_wrapper" bits
    if [ "${LD_PRELOAD:-}" = '/usr/lib/libnss_wrapper.so' ]; then
        rm -f "$NSS_WRAPPER_PASSWD" "$NSS_WRAPPER_GROUP"
        unset LD_PRELOAD NSS_WRAPPER_PASSWD NSS_WRAPPER_GROUP
    fi
}

function docker_init_socket_tmp(){
    if [ ! -d ${PGHOST} ]; then
        mkdir ${PGHOST}
    fi
}


#########################
## Init openGauss user ##
#########################

# Execute sql script, passed via stdin (or -f flag of pqsl)
# usage: docker_process_sql [gsql-cli-args]
#    ie: docker_process_sql --dbname=mydb <<<'INSERT ...'
#    ie: docker_process_sql -f my-file.sql
#    ie: docker_process_sql <my-file.sql
function docker_process_sql() {
    local query_runner=( gsql -v ON_ERROR_STOP=1 --username "$GS_USER" --password "$GS_PASSWORD")
    if [ -n "$GS_DB" ]; then
        query_runner+=( --dbname "$GS_DB" )
    fi
    if [ -n "$GS_PORT" ]; then
        query_runner+=( --port "$GS_PORT" )
    fi

    echo "Execute SQL: ${query_runner[@]} $@"
    "${query_runner[@]}" "$@"
}


function docker_init_user() {
    query_runner=( gsql -v ON_ERROR_STOP=1 --username "$GS_USER")
    if [ -n "$GS_DB" ]; then
        query_runner+=( --dbname "$GS_DB" )
    else
        GS_USER=$USER
    fi
    if [ -n "$GS_PORT" ]; then
        query_runner+=( --port "$GS_PORT" )
    fi
    echo "initialize password for user $GS_USER"
    echo
    gsql -v ON_ERROR_STOP=1 -d postgres --set user="$GS_USER" <<EOF
        ALTER ROLE :"user" PASSWORD $GS_PASSWORD;
EOF
}

function docker_setup_user() {
    query_runner=( gsql -v ON_ERROR_STOP=1 --username "$GS_USER" --password "$GS_PASSWORD")
    if [ -n "$GS_DB" ]; then
        query_runner+=( --dbname "$GS_DB" )
    fi
    if [ -n "$GS_PORT" ]; then
        query_runner+=( --port "$GS_PORT" )
    fi
    if [ -n "$GS_USERNAME" ]; then
        $query_runner --dbname postgres --set user="$GS_USERNAME" <<EOF
        create user :"user" SYSADMIN REPLICATION password $GS_PASSWORD;
EOF
    else
        echo " default user is $GS_USER"
    fi
}

function docker_setup_rep_user() {
    if [ -n "$SERVER_MODE" ] && [ "$SERVER_MODE" = "primary" ]; then
        GS_DB= docker_process_sql --dbname postgres --set passwd="$GS_PASSWORD" --set user="${GS_REPLUSER}" <<-'EOSQL'
        create user :"user" SYSADMIN REPLICATION password :"passwd" ;
EOSQL
    else
        echo " default no repuser created"
    fi
}

##################################
## Connfigure OpenGauss Cluster ##
###################################

# append parameter to postgres.conf for connections
function opengauss_setup_postgresql_conf() {
    #password_encryption_type = 2           
    #Password storage type, 0 is md5 for PG, 1 is sha256 + md5, 2 is sha256 only
    {
        echo
        if [ -n "$GS_PORT" ]; then
            echo "password_encryption_type = 0"
            echo "port = $GS_PORT"
            echo "wal_level = logical"
        else
            echo '# use default port 5432'
            echo "password_encryption_type = 0"
            echo "wal_level = logical"
        fi
        if [ -n "$NODE_NAME" ]; then
            echo "application_name = '$NODE_NAME'"
        fi

        if [ -n "$SERVER_MODE" ]; then
            echo "listen_addresses = '0.0.0.0'"
            echo "most_available_sync = on"
            echo "remote_read_mode = non_authentication"
            if [ -n "$SERVER_MODE" ]; then
                echo "pgxc_node_name = '$NODE_NAME'"
            fi
            if [ "$SERVER_MODE" = "primary" ]; then
               echo "max_connections = 20"
            else
               echo "max_connections = 20"
            fi
            echo -e "$REPL_CONN_INFO"
            if [ -n "$SYNCHRONOUS_STANDBY_NAMES" ]; then
               echo "synchronous_standby_names=$SYNCHRONOUS_STANDBY_NAMES"
            fi
        else
            echo "listen_addresses = '*'"
        fi

        if [ -n "$OTHER_PG_CONF" ]; then
            echo -e "$OTHER_PG_CONF"
        fi
        echo "modify_initial_password = false"
    } >> "$PGDATA/postgresql.conf"
}


function setup_opengauss_cluster_conf() {
    correct_network_ip=$(ip route show |grep -v default | grep $(ip route show | grep default | awk '{print $5}') | awk '{print $9}')
    host_array=(${PRIMARYHOST})
    standby_hosts=${STANDBYHOSTS}
    host_array+=(${standby_hosts//[,\"]/ })
    echo 
    echo "Cluster nodes: ${host_array[@]}"
    # It needs to enhance capture $correct_network_ip logic, if the host has 2 network interfaces.
    
    index=1
    
    echo "Configure openGauss replconninfo[X] on host ${correct_network_ip}."           
    for ((i = 0; i < ${#host_array[@]}; i++)); do
        if [ "${correct_network_ip}" != "${host_array[i]}" ]; then
            echo "replconninfo${index}='localhost=${correct_network_ip} localport=5433 localheartbeatport=5436 remotehost=${host_array[i]} remoteport=5433 remoteheartbeatport=5436'"
            gs_guc set -D ${PGDATA} -c "replconninfo${index}='localhost=${correct_network_ip} localport=5433 localheartbeatport=5436 remotehost=${host_array[i]} remoteport=5433 remoteheartbeatport=5436'"
            index=$(expr $index + 1)
        fi
        gs_guc set -D ${PGDATA} -h "host    all             $GS_USER             ${host_array[i]}/32           trust"
    done

    gs_guc set -D ${PGDATA} -c "password_encryption_type = 0"
    gs_guc set -D ${PGDATA} -c "max_connections = 20"
    if [ ${#host_array[@]} -le 2 ]; then
        echo "Keep cluster most available with set sync_most_available=on." 
        #gs_guc set -D ${PGDATA} -c "listen_addresses='*'"
        gs_guc set -D ${PGDATA} -c "most_available_sync=on"
    fi
}

function opengauss_setup_mot_conf() {
    echo "enable_numa = false" >> "$PGDATA/mot.conf"
}

# IPv4 local connections:
#host    all             all             127.0.0.1/32            trust
#host    all             omm             172.11.0.2/32           trust
#host    all             omm             172.11.0.3/32           trust
#host    all             hbu             0.0.0.0/0               md5
# append GS_HOST_AUTH_METHOD to pg_hba.conf for "host" connections
function opengauss_setup_hba_conf() {
    
    {
        echo
        if [ 'trust' = "$GS_HOST_AUTH_METHOD" ]; then
            echo '# warning trust is enabled for all connections'
            echo "host    all             all             0.0.0.0/0           md5"
        fi
        if [ -n "$GS_USERNAME" ];then
            echo "host    all             $GS_USERNAME             0.0.0.0/0           md5"
        fi
        if [ -n "$SERVER_MODE" ] && [ -n "$OG_SUBNET" ]; then
            #echo "host    replication     omm        127.0.0.1/32            trust"
            if [ -n "$GS_REPLUSER" ];then
                echo "host    replication     $GS_REPLUSER        $OG_SUBNET            trust"
            else
                echo "host    replication     sufe        $OG_SUBNET            trust"
            fi
        fi
    } >> "$PGDATA/pg_hba.conf"
    #if [ -n "$SERVER_MODE" ] && [ -n "$OG_SUBNET" ]; then
    #    sed -i "/# IPv6 local connections:/a host all omm $OG_SUBNET trust" $PGDATA/pg_hba.conf
    #fi
}

###########################################
## Init OpenGauss Cluster with OM and CM ##
###########################################

function generate_xml() {
    echo "python3 /generatexml.py --primary-host=${PRIMARYHOST} --standby-host=${STANDBYHOSTS} --primary-hostname=${PRIMARYNAME} --standby-hostname=${STANDBYNAMES}"
    python3 /generatexml.py --primary-host=${PRIMARYHOST} --standby-host=${STANDBYHOSTS} --primary-hostname=${PRIMARYNAME} --standby-hostname=${STANDBYNAMES}
    if [ ! -f "${GAUSSDATA}/cluster.xml" ]; then
        echo "generate cluster xml file failed."
        exit 1
    fi
    echo "generate cluster xml file success."
}

function generate_static_config_file() {
    if [ -f ${CM_HOME}/bin/cluster_static_config ]; then
        rm ${CM_HOME}/bin/cluster_static_config
    fi
    gs_om -t generateconf -X ${GAUSSDATA}/cluster.xml
    if [ $? -ne 0 ]; then
        echo "generate static config file failed..."
        exit 1
    fi
    cp ${GPHOME}/script/static_config_files/cluster_static_config_${hostname} ${CM_HOME}/bin/cluster_static_config
    cp ${GPHOME}/version.cfg ${GAUSSHOME}/bin/upgrade_version
}

function get_nodeid() {
    nodeid=-1
    c=0
    for line in $(cm_ctl view | grep ^node); do
        account=$line
        accounts[$c]=$account
        if [ "$account" == "nodeName:$hostname" ]; then
            strings=${accounts[$c - 1]}
            array=(${strings//\:/ })
            nodeid=${array[-1]}
            break
        fi
        ((c++))
    done
    echo $nodeid
    return
}

function init_cm_config() {
    if [ ! -d ${GAUSS_CM_DIR} ]; then
        mkdir -p ${GAUSS_CM_DIR}/{cm_server,cm_agent,sslcert}
    fi
    cp ${CM_HOME}/share/config/cm_server.conf.sample ${GAUSS_CM_DIR}/cm_server/cm_server.conf
    cp ${CM_HOME}/share/config/cm_agent.conf.sample ${GAUSS_CM_DIR}/cm_agent/cm_agent.conf

    nodeid=$(get_nodeid)
    if [ $nodeid == -1 ]; then
        echo "could not found nodeid of ${hostname}"
        exit 1
    fi
    echo "Get node id: ${nodeid} for ${hostname}"
    cmserver_log=${GAUSSLOG}/cm/cm_server
    cmagent_log=${GAUSSLOG}/cm/cm_agent
    cm_ctl set --param --server -k log_dir="'${cmserver_log}'" -n $nodeid
    cm_ctl set --param --agent -k log_dir="'${cmagent_log}'" -n $nodeid
    cm_ctl set --param --agent -k unix_socket_directory="'${GPHOME}'" -n $nodeid
    cm_ctl set --param --agent -k enable_ssl="off" -n $nodeid
    cm_ctl set --param --server -k enable_ssl="off" -n $nodeid
}

# expect_encrypt "cmd" "password" "success info"
function expect_encrypt() {
    /usr/bin/expect <<-EOF
        set timeout -1
        spawn $1
        expect {
                "*yes/no" { send "yes\r"; exp_continue }
                "*password:" { send "$2\r"; exp_continue }
                "*password again:" { send "$2\r"; exp_continue }
                "*$3*" { exit }
        }
        expect eof
EOF
    if [ $? == 0 ]; then
        return 0
    else
        return 1
    fi
}

function generate_cm_cert() {
    client_cmd="cm_ctl encrypt -M client -D ${GAUSS_CM_DIR}/sslcert"
    server_cmd="cm_ctl encrypt -M server -D ${GAUSS_CM_DIR}/sslcert"
    expect_encrypt "${client_cmd}" "${GS_PASSWORD}" "encrypt success."
    expect_encrypt "${server_cmd}" "${GS_PASSWORD}" "encrypt success."
}


function check_env_hosts() {
    primary_host=$(echo ${PRIMARYHOST} | sed 's/ //g')
    if [ "${primary_host}" == "" ]; then
        echo "Primary host is empty, at least one primary and one standby host are needed."
        exit 1
    fi
    standby_hosts=$(echo ${STANDBYHOSTS} | sed 's/ //g')
    if [ "${standby_hosts}" == "" ]; then
        echo "Standby hosts are empty, at least one primary and one standby host are needed."
        exit 1
    fi
    primary_name=$(echo ${PRIMARYNAME} | sed 's/ //g')
    if [ "${primary_name}" == "" ]; then
        echo "Primary name is empty, at least one primary and one standby host are needed."
        exit 1
    fi

    standby_names=$(echo ${STANDBYNAMES} | sed 's/ //g')
    if [ "${standby_names}" == "" ]; then
        echo "Standby names are empty, at least one primary and one standby host are needed."
        exit 1
    fi
}

function set_authorized_keys() {
    echo 
    echo "start to set authorized_keys mechanism for user ${USER}"
    echo
    if [ -f ${authorized_key_dir}/id_rsa ];then
        cp ${authorized_key_dir}/id_rsa  $HOME/.ssh
    fi
    if [ -f ${authorized_key_dir}/authorized_keys ];then
        cp ${authorized_key_dir}/authorized_keys  $HOME/.ssh
    fi
    if [ -f ${HOME}/.ssh/id_rsa ] && [ -f ${HOME}/.ssh/authorized_keys ];then
        chmod 600 $HOME/.ssh/{id_rsa,authorized_keys}
        echo "Set authorized_keys mechanism successfully"
    else
        echo "Set authorized_keys mechanism failed, need to repair trust keys for user ${USER}..."
    fi
}

function start_monitor_dead_loop() {
    i=1
    while ((i > 0)); do
        monitor_proc=$(ps -aux | grep om_monitor | grep -v grep)
        #check if process exist
        if [ "${monitor_proc}" == "" ]; then
            source ${ENVFILE}
            echo 
            echo "Startup om_monitor process..."
            echo "om_monitor -L $GAUSSLOG/cm/om_monitor"
            nohup om_monitor -L $GAUSSLOG/cm/om_monitor &
        fi
        #check if process SIGSTOP(kill -19)
        proc_stat=$(echo $monitor_proc | awk '{print $8}')
        if [[ $proc_stat = T* ]]; then
            echo "om_monitor process has been hung up. wake up it."
            pid=$(echo $monitor_proc | awk '{print $2}')
            kill -18 ${pid}
        fi
        sleep 60
    done
}

#############################################
## Check openGauss instance and CM Cluster ##
#############################################

function check_component_state(){
    n_process=0
    i=1
    sleep 30
    for ((i=1;i<=5;i++)); do
        n_cm_agent_process=$(ps -ef | grep cm_agent | grep -v  grep | wc -l)
        n_cm_server_process=$(ps -ef | grep cm_server | grep -v  grep | wc -l)
        n_gaussdb_process=$(ps -ef | grep gaussdb | grep $PGDATA | wc -l)
        echo 
        #echo "$n_cm_agent_process $n_cm_server_process $n_gaussdb_process"
        if [ ${n_cm_agent_process} -eq 1 ] && [ ${n_cm_server_process} -eq 1 ] && [ ${n_gaussdb_process} -eq 1 ];then
            echo "CM agent, server and openGauss instance is running at host=${hostname}." 
            n_process=3
            #echo "Wait 30 seconds to ensure replication process built in openGauss cluster." 
            break
        fi
        echo "Abnormal porcess $n_cm_agent_process $n_cm_server_process $n_gaussdb_process"
        sleep 30
    done
    # It can be removed if we find a way to ensure CM Server in healthy status.
    # Be care of to check the CM server cluster's status
    #sleep 60
    #echo "Check CM server cluster's status, and exit if code is not 0." 
    #cm_ctl query
}

function check_cluster_state(){
    set +e
    echo "Check openGauss receiver number."
    for ((i=1;i<=5;i++));do
        n_receiver=$(gs_ctl query | grep channel | wc -l)
        echo "At loop $i, get receiver number=${n_receiver} at host ${hostname}"
        if [ ${n_receiver} -gt 0 ];then
            break
        fi
        sleep 30
    done
    if [ $n_receiver -ne 0 ];then
        for ((i=1;i<=5;i++)); do
            cluster_state=$(cm_ctl query | grep cluster_state | awk -F ':' '{print $2}'|awk '{$1=$1};1')
            echo 
            echo "At loop $i, openGauss Cluster is running in state ${cluster_state}"
            echo "cluster_state             : ${cluster_state}"
            if [ "x$cluster_state" = "xNormal" ] || [ "x$cluster_state" = "xDegraded" ];then
                break
            fi
            sleep 90
        done
    else
        echo 
        echo "Receiver is Not Found in openGauss cluster"
    fi
    set -e

}
function __log(){
    message=$@
    filename=$(basename $0)
    echo "$(date "+%Y-%m-%d %T") [$USER] [$filename] $message"
}

function main() {
    set_envfile 
    docker_setup_env
    # only run initialization on an empty data directory
    if [ -z "$DATABASE_ALREADY_EXISTS" ]; then 
        docker_verify_minimum_env
        # check dir permissions to reduce likelihood of half-initialized database
        # ls /docker-entrypoint-initdb.d/ > /dev/null       
        # env
        __log "Start to initializes an openGauss database cluster"
        docker_init_database
        __log "Create socket tmp directory ${PGHOST}"
        docker_init_socket_tmp
        echo "Initialize openGauss instance complete"
        echo
        echo "Setup configure items for openGauss instances"
        opengauss_setup_postgresql_conf
        opengauss_setup_hba_conf
        if [ $GAUSS_EDITION != "lite" ];then
            opengauss_setup_mot_conf
        fi
        # PGPASSWORD is required for gsql when authentication is required for 'local' connections via pg_hba.conf and is otherwise harmless
        # e.g. when '--auth=md5' or '--auth-local=md5' is used in POSTGRES_INITDB_ARGS
        export PGPASSWORD="${PGPASSWORD:-$GS_PASSWORD}"
        if [ -n "$STANDBYHOSTS" ]; then
            __log  "Setup configure items for openGauss cluster"
            setup_opengauss_cluster_conf
            echo 
            __log  "Generate openGauss cluster configure files with manage panel CM"
            generate_xml
            generate_static_config_file
            init_cm_config
            generate_cm_cert
            set_authorized_keys
            cd $GAUSSDATA
            __log  "Startup om_monitor process..."
            echo "om_monitor -L $GAUSSLOG/cm/om_monitor &"
            nohup om_monitor -L $GAUSSLOG/cm/om_monitor &
            echo 
            __log "Start to check openGauss components state..."
            check_component_state
            __log "Start to check openGauss cluster state..."
            echo 
            check_cluster_state
            echo 
            __log "Get openGuass cluster_state=${cluster_state}"
            if [ "x$cluster_state" = "xNormal" ] || [ "x$cluster_state" = "xDegraded" ];then
                SERVER_MODE=$(gs_ctl query | grep local_role |uniq | awk '{print $3}')
                if [ "$SERVER_MODE" = "Primary" ];then
                    __log "Start to setup users at host ${hostname} with SERVER_MODE=${SERVER_MODE}"
                    set +e
                    docker_setup_user
                    if [ -n "${GS_REPLUSER}" ];then
                        docker_setup_rep_user
                    fi
                    set -e
                fi
            fi
            # if [ "$SERVER_MODE" = "primary" ];then
            #     echo "Initialize and setup openGuass users for default, admin and replication"
            #     if [ "x$cluster_state" = "xNormal" ] || [ "x$cluster_state" = "xDegraded" ];then
            #         set +e
            #         docker_init_user
            #         docker_setup_user
            #         if [ -n "${GS_REPLUSER}" ];then
            #             docker_setup_rep_user
            #         fi
            #         set -e
            #     fi
            #fi
            echo
            __log "Keep om_monitor process alive with a dead loop"
            start_monitor_dead_loop
        else
            ## to-do: add initialize single node bussiness logic
            echo "Initialize an openGauss install with single node..."
            #docker_start_server "$@" 
        fi
    else
        ## to-do: add initialize single node bussiness logic
        echo
        __log 'openGauss Database directory appears to contain a database; skipping initialization'
        echo
        cd $GAUSSDATA
        set +e
        start_monitor_dead_loop
        exit 0
    fi

 
}

if ! _is_sourced; then
    main "$@"
fi